/* Project 7 Virtual Machine
   File: parser.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "parser.h"

/* Creates a VirtualMachineState with everything initialized
   to 0 {Brad Klingensmith} */
struct VirtualMachineState Create_Virtual_Machine()
{
	int i;
	struct VirtualMachineState virtual_machine;
	virtual_machine.instruction_count = 0;
	virtual_machine.instruction_index = 0;
	virtual_machine.instructions = NULL;

	for (i = 0; i < REGISTERCOUNT; ++i)
	{
		virtual_machine.registers[i].t = INTEGER;
		virtual_machine.registers[i].v.i = 0;
	}
	return virtual_machine;
}

/* Frees any memory allocated inside the virtual machine {Brad Klingensmith} */
void Free_VirtualMachine(struct VirtualMachineState *virtual_machine)
{
	if (virtual_machine->instructions)
	{
		free (virtual_machine->instructions);
		virtual_machine->instructions = 0;
	}
}

/* Checks to see if a label exists in list of tokens (Brad Klingensmith} */
int Verify_Label(char *lbl, struct TokenList token_list)
{
	struct Token *token = token_list.head;

	for (; token != NULL; token = token->next)
	{
		if (token->type == LABEL)
		{
			if (strcmp(token->v.lbl, lbl) == 0)
				return 1;
		}
	}
	return 0;
}

/* Creates the instruction list in the virtual machine from 
   the linked list of tokens {Brad Klingensmith} */
int Create_Instruction_Set(struct VirtualMachineState *virtual_machine,
						struct TokenList token_list, FILE* error_file)
{
	struct Token *token = token_list.head;
	int i;

	/* Count the number of instructions */
	virtual_machine->instruction_count = 0;
	for (; token != NULL; token = token->next)
	{
		if (token->type == OPCODE || token->type == LABEL)
			virtual_machine->instruction_count++;
	}

	/* Allocate memory for the instructions */
	virtual_machine->instructions = (struct Instruction*)malloc(sizeof(struct Instruction) * virtual_machine->instruction_count);

	/* Convert the list of tokens into an instruction set */
	token = token_list.head;
	for (i = 0; i < virtual_machine->instruction_count; ++i)
	{
		/* Skip random tokens */
		while (token->type != OPCODE && token->type != LABEL)
		{
			fprintf(error_file, "Line %d failed token\n", token->line_num);
			Print_Token(token, error_file);
			return 0;
		}
		/* Check for a label */
		if (token->type == LABEL)
		{
			virtual_machine->instructions[i].f = Label_Func;
			virtual_machine->instructions[i].p1.v.lbl = token->v.lbl;
			token = token->next;
		}
		else
		{
			/*MOV = 0, ADD = 1, SUB = 2, MUL = 3, DIV = 4, 
			 GET = 5, FGET = 6, PUT = 7, JMNZ = 8, JMZ = 9, 
			 JMP = 10, JMN = 11, GOTO = 12*/
			if (token->v.op == MOV)
			{
				virtual_machine->instructions[i].f = Mov_Func;

				/* Check the type */
				token = token->next;
				if (token->type != REGISTER)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p1.t = REGISTER;
					virtual_machine->instructions[i].p1.v.r = token->v.r;
				}
				
				token = token->next;
				if (token->type == OPCODE || token->type == LABEL)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p2.t = token->type;
					if (token->type == STRING)					
						virtual_machine->instructions[i].p2.v.str = token->v.str;
					if (token->type == INTEGER)					
						virtual_machine->instructions[i].p2.v.i = token->v.i;
					if (token->type == FLOAT)					
						virtual_machine->instructions[i].p2.v.f = token->v.f;
					if (token->type == REGISTER)					
						virtual_machine->instructions[i].p2.v.r = token->v.r;
				}
				token = token->next;
			}
			else if (token->v.op == ADD)
			{
				virtual_machine->instructions[i].f = Add_Func;

				/* Check the type */
				token = token->next;
				if (token->type != REGISTER)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p1.t = REGISTER;
					virtual_machine->instructions[i].p1.v.r = token->v.r;
				}
				
				token = token->next;
				if (token->type == OPCODE || token->type == LABEL || token->type == STRING)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p2.t = token->type;
					if (token->type == INTEGER)					
						virtual_machine->instructions[i].p2.v.i = token->v.i;
					if (token->type == FLOAT)					
						virtual_machine->instructions[i].p2.v.f = token->v.f;
					if (token->type == REGISTER)					
						virtual_machine->instructions[i].p2.v.r = token->v.r;
				}
				token = token->next;
			}
			else if (token->v.op == SUB)
			{
				virtual_machine->instructions[i].f = Sub_Func;

				/* Check the type */
				token = token->next;
				if (token->type != REGISTER)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p1.t = REGISTER;
					virtual_machine->instructions[i].p1.v.r = token->v.r;
				}
				
				token = token->next;
				if (token->type == OPCODE || token->type == LABEL || token->type == STRING)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p2.t = token->type;
					if (token->type == INTEGER)					
						virtual_machine->instructions[i].p2.v.i = token->v.i;
					if (token->type == FLOAT)					
						virtual_machine->instructions[i].p2.v.f = token->v.f;
					if (token->type == REGISTER)					
						virtual_machine->instructions[i].p2.v.r = token->v.r;
				}
				token = token->next;
			}
			else if (token->v.op == MUL)
			{
				virtual_machine->instructions[i].f = Mul_Func;

				/* Check the type */
				token = token->next;
				if (token->type != REGISTER)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p1.t = REGISTER;
					virtual_machine->instructions[i].p1.v.r = token->v.r;
				}
				
				token = token->next;
				if (token->type == OPCODE || token->type == LABEL || token->type == STRING)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p2.t = token->type;
					if (token->type == INTEGER)					
						virtual_machine->instructions[i].p2.v.i = token->v.i;
					if (token->type == FLOAT)					
						virtual_machine->instructions[i].p2.v.f = token->v.f;
					if (token->type == REGISTER)					
						virtual_machine->instructions[i].p2.v.r = token->v.r;
				}
				token = token->next;
			}
			else if (token->v.op == DIV)
			{
				virtual_machine->instructions[i].f = Div_Func;

				/* Check the type */
				token = token->next;
				if (token->type != REGISTER)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p1.t = REGISTER;
					virtual_machine->instructions[i].p1.v.r = token->v.r;
				}
				
				token = token->next;
				if (token->type == OPCODE || token->type == LABEL || token->type == STRING)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p2.t = token->type;
					if (token->type == INTEGER)					
						virtual_machine->instructions[i].p2.v.i = token->v.i;
					if (token->type == FLOAT)					
						virtual_machine->instructions[i].p2.v.f = token->v.f;
					if (token->type == REGISTER)					
						virtual_machine->instructions[i].p2.v.r = token->v.r;
				}
				token = token->next;
			}
			else if (token->v.op == JMNZ)
			{
				virtual_machine->instructions[i].f = Jmnz_Func;

				/* Check the type */
				token = token->next;
				if (token->type == OPCODE || token->type == LABEL || token->type == STRING)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p1.t = token->type;
					if (token->type == INTEGER)					
						virtual_machine->instructions[i].p1.v.i = token->v.i;
					if (token->type == FLOAT)					
						virtual_machine->instructions[i].p1.v.f = token->v.f;
					if (token->type == REGISTER)					
						virtual_machine->instructions[i].p1.v.r = token->v.r;
				}
				
				token = token->next;
				if (token->type != STRING)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p2.t = LABEL;
					virtual_machine->instructions[i].p2.v.lbl = token->v.lbl;
					if (!Verify_Label(token->v.lbl, token_list))
					{
						fprintf(error_file, "Line %d: Label not found\n", token->line_num);
						Print_Token(token, error_file);
						return 0;
					}
				}
				token = token->next;
			}
			else if (token->v.op == JMZ)
			{
				virtual_machine->instructions[i].f = Jmz_Func;

				/* Check the type */
				token = token->next;
				if (token->type == OPCODE || token->type == LABEL || token->type == STRING)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p1.t = token->type;
					if (token->type == INTEGER)					
						virtual_machine->instructions[i].p1.v.i = token->v.i;
					if (token->type == FLOAT)					
						virtual_machine->instructions[i].p1.v.f = token->v.f;
					if (token->type == REGISTER)					
						virtual_machine->instructions[i].p1.v.r = token->v.r;
				}
				
				token = token->next;
				if (token->type != STRING)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p2.t = LABEL;
					virtual_machine->instructions[i].p2.v.lbl = token->v.lbl;
					if (!Verify_Label(token->v.lbl, token_list))
					{
						fprintf(error_file, "Line %d: Label not found\n", token->line_num);
						Print_Token(token, error_file);
						return 0;
					}
				}
				token = token->next;
			}
			else if (token->v.op == JMP)
			{
				virtual_machine->instructions[i].f = Jmp_Func;

				/* Check the type */
				token = token->next;
				if (token->type == OPCODE || token->type == LABEL || token->type == STRING)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p1.t = token->type;
					if (token->type == INTEGER)					
						virtual_machine->instructions[i].p1.v.i = token->v.i;
					if (token->type == FLOAT)					
						virtual_machine->instructions[i].p1.v.f = token->v.f;
					if (token->type == REGISTER)					
						virtual_machine->instructions[i].p1.v.r = token->v.r;
				}
				
				token = token->next;
				if (token->type != STRING)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p2.t = LABEL;
					virtual_machine->instructions[i].p2.v.lbl = token->v.lbl;
					if (!Verify_Label(token->v.lbl, token_list))
					{
						fprintf(error_file, "Line %d: Label not found\n", token->line_num);
						Print_Token(token, error_file);
						return 0;
					}
				}
				token = token->next;
			}
			else if (token->v.op == JMN)
			{
				virtual_machine->instructions[i].f = Jmn_Func;

				/* Check the type */
				token = token->next;
				if (token->type == OPCODE || token->type == LABEL || token->type == STRING)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p1.t = token->type;
					if (token->type == INTEGER)					
						virtual_machine->instructions[i].p1.v.i = token->v.i;
					if (token->type == FLOAT)					
						virtual_machine->instructions[i].p1.v.f = token->v.f;
					if (token->type == REGISTER)					
						virtual_machine->instructions[i].p1.v.r = token->v.r;
				}
				
				token = token->next;
				if (token->type != STRING)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p2.t = LABEL;
					virtual_machine->instructions[i].p2.v.lbl = token->v.lbl;
					if (!Verify_Label(token->v.lbl, token_list))
					{
						fprintf(error_file, "Line %d: Label not found\n", token->line_num);
						Print_Token(token, error_file);
						return 0;
					}
				}
				token = token->next;
			}
			else if (token->v.op == GOTO)
			{
				virtual_machine->instructions[i].f = Goto_Func;

				/* Check the type */
				token = token->next;				
				if (token->type != STRING)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p1.t = LABEL;
					virtual_machine->instructions[i].p1.v.lbl = token->v.lbl;
					if (!Verify_Label(token->v.lbl, token_list))
					{
						fprintf(error_file, "Line %d: Label not found\n", token->line_num);
						Print_Token(token, error_file);
						return 0;
					}
				}
				token = token->next;
			}
			else if (token->v.op == GET)
			{
				virtual_machine->instructions[i].f = Get_Func;

				/* Check the type */
				token = token->next;				
				if (token->type != REGISTER)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p1.t = REGISTER;
					virtual_machine->instructions[i].p1.v.r = token->v.r;
				}
				token = token->next;
			}
			else if (token->v.op == FGET)
			{
				virtual_machine->instructions[i].f = Fget_Func;

				/* Check the type */
				token = token->next;				
				if (token->type != REGISTER)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p1.t = REGISTER;
					virtual_machine->instructions[i].p1.v.r = token->v.r;
				}
				token = token->next;
			}
			else if (token->v.op == PUT)
			{
				virtual_machine->instructions[i].f = Put_Func;

				/* Check the type */
				token = token->next;				
				if (token->type != REGISTER && token->type != INTEGER && 
					token->type != FLOAT && token->type != STRING)
				{
					fprintf(error_file, "Line %d failed token\n", token->line_num);
					Print_Token(token, error_file);
					return 0;
				}
				else
				{
					virtual_machine->instructions[i].p1.t = token->type;
					if (token->type == STRING)					
						virtual_machine->instructions[i].p1.v.str = token->v.str;
					if (token->type == INTEGER)					
						virtual_machine->instructions[i].p1.v.i = token->v.i;
					if (token->type == FLOAT)					
						virtual_machine->instructions[i].p1.v.f = token->v.f;
					if (token->type == REGISTER)					
						virtual_machine->instructions[i].p1.v.r = token->v.r;
				}
				token = token->next;
			}
		}
	}

	return 1;
}

/* Loops through the code and executes it {Brad Klingensmith} */
void Execute_Code(struct VirtualMachineState *virtual_machine)
{
	virtual_machine->instruction_index = 0;
	while (virtual_machine->instruction_index < virtual_machine->instruction_count)
	{
		/* Call the function */
	//	printf("%d\n", virtual_machine->instruction_index);
		(*virtual_machine->instructions[virtual_machine->instruction_index].f)(virtual_machine, virtual_machine->instructions[virtual_machine->instruction_index].p1, virtual_machine->instructions[virtual_machine->instruction_index].p2);
	}
}

/* Labels don't change the state.  Just a placeholder {Brad Klingensmith} */
void Label_Func(struct VirtualMachineState *virtual_machine, struct Parameter p1, struct Parameter p2)
{
	virtual_machine->instruction_index++;
}

//when called, jumps to the index for p1 {Matt Sparkman}
void Goto_Func(struct VirtualMachineState *virtual_machine, struct Parameter p1, struct Parameter p2)
{
	//p1.v.label is the name of the label that you want to go to
      	int i;
	//loops through the instruction count to add
        for (i = 0; i < virtual_machine->instruction_count; ++i)
        {	
        	if (virtual_machine->instructions[i].f == Label_Func)
                {	// instructions[i].p1.v.label is the label's name
                	if (strcmp(virtual_machine->instructions[i].p1.v.lbl, p1.v.lbl) == 0)
                       	{	//moves the index after the one we wanted
                        	virtual_machine->instruction_index = i;
                                return;
                        }
                }
        }
}
//when called, jumps to the index of p2 if p1 is not equal to zero	{Matt Sparkman}
void Jmnz_Func(struct VirtualMachineState *virtual_machine, struct Parameter p1, struct Parameter p2)
{	//checks if p1 is a float
	if (p1.t == FLOAT)
	{	//if p1 is not equal to zero...
		if (p1.v.f != 0)
		{	//...jump to p2
			Goto_Func(virtual_machine, p2, p1);
		}
	}
	// " " is an integer
	else if (p1.t == INTEGER)
	{	//if p1 is not equal to zero...
		if (p1.v.i != 0)
		{	//...jump to p2
			Goto_Func(virtual_machine, p2, p1);
		}
	}
	// " " is a register
	else if (p1.t == REGISTER)
	{	//check if the register is a float
		if (virtual_machine->registers[p1.v.r].t == FLOAT)
		{	//if p1 is not equal to zero...
			if (virtual_machine->registers[p1.v.r].v.f != 0)
			{	//...jump to p2
				Goto_Func(virtual_machine, p2, p1);
			}
		}
		//or check if it is an integer
		else if (virtual_machine->registers[p1.v.r].t == INTEGER)
		{	//if p1 is not equal to zero...
			if (virtual_machine->registers[p1.v.r].v.i != 0)
			{	//...jump to p2
				Goto_Func(virtual_machine, p2, p1);
			}
		}
	}
	virtual_machine->instruction_index++;
}
//when called, jumps to the index of p2 if p1 is equal to zero	{Matt Sparkman}
void Jmz_Func(struct VirtualMachineState *virtual_machine, struct Parameter p1, struct Parameter p2)
{	//checks if p1 is a float,
	if (p1.t == FLOAT)
	{	//if p1 is equal to zero...
		if (p1.v.f == 0)
		{	//...jump to p2
			Goto_Func(virtual_machine, p2, p1);
		}
	}
	// " " is an integer
	else if (p1.t == INTEGER)
	{	//if p1 is equal to zero...
		if (p1.v.i == 0)
		{	//...jump to p2
			Goto_Func(virtual_machine, p2, p1);
		}
	}
	// " " is a register
	else if (p1.t == REGISTER)
	{	//check if the register is a float
		if (virtual_machine->registers[p1.v.r].t == FLOAT)
		{	//if p1 is equal to zero...
			if (virtual_machine->registers[p1.v.r].v.f == 0)
			{	//...jump to p2
				Goto_Func(virtual_machine, p2, p1);
			}
		}
		//or check if it is an integer
		else if (virtual_machine->registers[p1.v.r].t == INTEGER)
		{	//if p1 is equal to zero...
			if (virtual_machine->registers[p1.v.r].v.i == 0)
			{	//...jump to p2
				Goto_Func(virtual_machine, p2, p1);
			}
		}
	}
	virtual_machine->instruction_index++;
}
//when called, jumps to the index of p2 if p1 is positive	{Matt Sparkman}
void Jmp_Func(struct VirtualMachineState *virtual_machine, struct Parameter p1, struct Parameter p2)
{	//checks if p1 is a float
	if (p1.t == FLOAT)
	{	//if p1 is positive...
		if (p1.v.f > 0)
		{	//...jump to p2
			Goto_Func(virtual_machine, p2, p1);
		}
	}
	// " " is an integer
	else if (p1.t == INTEGER)
	{	//if p1 is positive...
		if (p1.v.i > 0)
		{	//...jump to p2
			Goto_Func(virtual_machine, p2, p1);
		}
	}
	// " " is a register
	else if (p1.t == REGISTER)
	{	//check if the register is a float
		if (virtual_machine->registers[p1.v.r].t == FLOAT)
		{	//if p1 is positive...
			if (virtual_machine->registers[p1.v.r].v.f > 0)
			{	//...jump to p2
				Goto_Func(virtual_machine, p2, p1);
			}
		}
		//or check if it is an integer
		else if (virtual_machine->registers[p1.v.r].t == INTEGER)
		{	//if p1 is positive...
			if (virtual_machine->registers[p1.v.r].v.i > 0)
			{	//...jump to p2
				Goto_Func(virtual_machine, p2, p1);
			}
		}
	}
	virtual_machine->instruction_index++;
}

//when called, jumps to the index of p2 if p1 is negative	{Matt Sparkman}
void Jmn_Func(struct VirtualMachineState *virtual_machine, struct Parameter p1, struct Parameter p2)
{	//checks if p1 is a float
	if (p1.t == FLOAT)
	{	//if p1 is negative...
		if (p1.v.f < 0)
		{	//...jump to p2
			Goto_Func(virtual_machine, p2, p1);
		}
	}
	// " " is an integer
	else if (p1.t == INTEGER)
	{	//if p1 is negative...
		if (p1.v.i < 0)
		{	//...jump to p2
			Goto_Func(virtual_machine, p2, p1);
		}
	}
	// " " is a register
	else if (p1.t == REGISTER)
	{	//check if the register is a float
		if (virtual_machine->registers[p1.v.r].t == FLOAT)
		{	//if p1 is negative...
			if (virtual_machine->registers[p1.v.r].v.f < 0)
			{	//...jump to p2
				Goto_Func(virtual_machine, p2 ,p1);
			}
		}
		//or check if it is an integer
		else if (virtual_machine->registers[p1.v.r].t == INTEGER)
		{	//if p1 is negative...
			if (virtual_machine->registers[p1.v.r].v.i < 0)
			{	//...jump to p2
				Goto_Func(virtual_machine, p2, p1);
			}
		}
	}
	virtual_machine->instruction_index++;
}

//MOV: moves the value of p2 to the register p1 {Abdullah Alosayef}
void Mov_Func(struct VirtualMachineState *virtual_machine, struct Parameter p1, struct Parameter p2) 
{ 
	// p1 will also be a register or it won't compile 
	// Check if p2 is an integer 
	if (p2.t == INTEGER) 
	{ 
		virtual_machine->registers[p1.v.r].t = INTEGER; 
		virtual_machine->registers[p1.v.r].v.i = p2.v.i; 
	} 
	// Check if p2 is a float 
	if (p2.t == FLOAT) 
	{ 
		virtual_machine->registers[p1.v.r].t = FLOAT; 
		virtual_machine->registers[p1.v.r].v.f = p2.v.f; 
	} 
	// Check if p2 is a register 
	else if (p2.t == REGISTER) 
	{ 
		virtual_machine->registers[p1.v.r].t = virtual_machine->registers[p2.v.r].t; 
		virtual_machine->registers[p1.v.r].v = virtual_machine->registers[p2.v.r].v; 
	} 

	virtual_machine->instruction_index++;
} 

//ADD: adds the value of p2 to the register p1     {Abdullah Alosayef}
void Add_Func(struct VirtualMachineState *virtual_machine, struct Parameter p1, struct Parameter p2) 
{ 
	// p1 will also be a register or it won't compile 
	
	// if p2 is an integer 
	if (p2.t == INTEGER) 
	{
		if(virtual_machine->registers[p1.v.r].t == INTEGER)
		{
			//do the addition
			// storiing the result in an integer
			virtual_machine->registers[p1.v.r].v.i += p2.v.i; 
		}
		if(virtual_machine->registers[p1.v.r].t == FLOAT)
		{
			virtual_machine->registers[p1.v.r].t = FLOAT;
			//do the addition
			// storiing the result in a float
			virtual_machine->registers[p1.v.r].v.f = virtual_machine->registers[p1.v.r].v.i + p2.v.f;
		}
	} 
	
	// if p2 is a float 
	if (p2.t == FLOAT) 
	{ 
		if(virtual_machine->registers[p1.v.r].t == INTEGER)
		{
			virtual_machine->registers[p1.v.r].t = FLOAT;
			//do the addition
			// storiing the result in a float
			virtual_machine->registers[p1.v.r].v.f += p2.v.i; 
		}
		if(virtual_machine->registers[p1.v.r].t == FLOAT)
		{
			virtual_machine->registers[p1.v.r].t = FLOAT;
			//do the addition
			// storiing the result in a float
			virtual_machine->registers[p1.v.r].v.f += p2.v.f; 
		}
	} 
	
	// if p2 is a register 
	else if (p2.t == REGISTER) 
	{ 
		if(virtual_machine->registers[p1.v.r].t == INTEGER)
		{
			// Check what p2's register holds
			if (virtual_machine->registers[p2.v.r].t == INTEGER)
			{
				// Add int to int
				virtual_machine->registers[p1.v.r].v.i += virtual_machine->registers[p2.v.r].v.i; 
			}
			// Check what p2's register holds
			if (virtual_machine->registers[p2.v.r].t == FLOAT)
			{
				// Add float to int store as float
				virtual_machine->registers[p1.v.r].t = FLOAT;
				virtual_machine->registers[p1.v.r].v.f = virtual_machine->registers[p1.v.r].v.i + virtual_machine->registers[p2.v.r].v.f; 
			} 
		}
		if(virtual_machine->registers[p1.v.r].t == FLOAT)
		{
			// Check what p2's register holds
			if (virtual_machine->registers[p2.v.r].t == INTEGER)
			{
				// Add float to int and store as float
				virtual_machine->registers[p1.v.r].v.f += virtual_machine->registers[p2.v.r].v.i; 
			}
			// Check what p2's register holds
			if (virtual_machine->registers[p2.v.r].t == FLOAT)
			{
				// Add float to float
				virtual_machine->registers[p1.v.r].v.f += virtual_machine->registers[p2.v.r].v.f; 
			}
		}
	}
	virtual_machine->instruction_index++;
}

//SUB: subtractes the value of p2 from the register p1     {Abdullah Alosayef}
void Sub_Func(struct VirtualMachineState *virtual_machine, struct Parameter p1, struct Parameter p2) 
{ 
	// p1 will also be a register or it won't compile 

	// if p2 is an integer 
	if (p2.t == INTEGER) 
	{
		if(virtual_machine->registers[p1.v.r].t == INTEGER)
		{
			virtual_machine->registers[p1.v.r].t = INTEGER;
			//do the subtraction
			// storing the result in an integer
			virtual_machine->registers[p1.v.r].v.i -= p2.v.i; 
		}
		if(virtual_machine->registers[p1.v.r].t == FLOAT)
		{
			virtual_machine->registers[p1.v.r].t = FLOAT;
			//do the subtraction
			// storing the result in a float
			virtual_machine->registers[p1.v.r].v.f = virtual_machine->registers[p1.v.r].v.i - p2.v.f;
		}
	} 
	
	// if p2 is a float 
	if (p2.t == FLOAT) 
	{ 
		if(virtual_machine->registers[p1.v.r].t == INTEGER)
		{
			virtual_machine->registers[p1.v.r].t = FLOAT;
			//do the subtraction
			// storing the result in a float
			virtual_machine->registers[p1.v.r].v.f -= p2.v.i; 
		}
		if(virtual_machine->registers[p1.v.r].t == FLOAT)
		{
			virtual_machine->registers[p1.v.r].t = FLOAT;
			//do the subtraction
			// storing the result in a float
			virtual_machine->registers[p1.v.r].v.f -= p2.v.f; 
		}
	} 
	
	// if p2 is a register 
	else if (p2.t == REGISTER) 
	{ 
		if(virtual_machine->registers[p1.v.r].t == INTEGER)
		{
			// Check what p2's register holds
			if (virtual_machine->registers[p2.v.r].t == INTEGER)
			{
				// subtracte int from int
				virtual_machine->registers[p1.v.r].v.i -= virtual_machine->registers[p2.v.r].v.i; 
			}
			// Check what p2's register holds
			if (virtual_machine->registers[p2.v.r].t == FLOAT)
			{
				// subtracte float from int and store as float
				virtual_machine->registers[p1.v.r].t = FLOAT;
				virtual_machine->registers[p1.v.r].v.f = virtual_machine->registers[p1.v.r].v.i - virtual_machine->registers[p2.v.r].v.f; 
			} 
		}
		if(virtual_machine->registers[p1.v.r].t == FLOAT)
		{
			// Check what p2's register holds
			if (virtual_machine->registers[p2.v.r].t == INTEGER)
			{
				// subtracte int from float
				virtual_machine->registers[p1.v.r].v.f -= virtual_machine->registers[p2.v.r].v.i; 
			}
			// Check what p2's register holds
			if (virtual_machine->registers[p2.v.r].t == FLOAT)
			{
				// subtracte float from float
				virtual_machine->registers[p1.v.r].v.f -= virtual_machine->registers[p2.v.r].v.f; 
			}
		} 
	}
	virtual_machine->instruction_index++;
}

//MUL: multiplys p2 by p1     {Abdullah Alosayef}
void Mul_Func(struct VirtualMachineState *virtual_machine, struct Parameter p1, struct Parameter p2) 
{ 
	// p1 will also be a register or it won't compile 

	// if p2 is an integer 
	if (p2.t == INTEGER) 
	{
		if(virtual_machine->registers[p1.v.r].t == INTEGER)
		{
			virtual_machine->registers[p1.v.r].t = INTEGER;
			//do the multiplication
			// storing the result in an integer
			virtual_machine->registers[p1.v.r].v.i *= p2.v.i; 
		}
		if(virtual_machine->registers[p1.v.r].t == FLOAT)
		{
			virtual_machine->registers[p1.v.r].t = FLOAT;
			//do the multiplication
			// storiing the result in a float
			virtual_machine->registers[p1.v.r].v.f = virtual_machine->registers[p1.v.r].v.i * p2.v.f;
		}
	} 
	
	// if p2 is a float 
	if (p2.t == FLOAT) 
	{ 
		if(virtual_machine->registers[p1.v.r].t == INTEGER)
		{
			virtual_machine->registers[p1.v.r].t = FLOAT;
			//do the multiplication
			// storing the result in a float
			virtual_machine->registers[p1.v.r].v.f *= p2.v.i; 
		}
		if(virtual_machine->registers[p1.v.r].t == FLOAT)
		{
			virtual_machine->registers[p1.v.r].t = FLOAT;
			//do the multiplication
			// storing the result in a float
			virtual_machine->registers[p1.v.r].v.f *= p2.v.f; 
		}
	} 
	
	// if p2 is a register 
	else if (p2.t == REGISTER) 
	{ 
		if(virtual_machine->registers[p1.v.r].t == INTEGER)
		{
			// Check what p2's register holds
			if (virtual_machine->registers[p2.v.r].t == INTEGER)
			{
				// multiply int by int
				virtual_machine->registers[p1.v.r].v.i *= virtual_machine->registers[p2.v.r].v.i; 
			}
			// Check what p2's register holds
			if (virtual_machine->registers[p2.v.r].t == FLOAT)
			{
				// multiply float by int and store as float
				virtual_machine->registers[p1.v.r].t = FLOAT;
				virtual_machine->registers[p1.v.r].v.f = virtual_machine->registers[p1.v.r].v.i * virtual_machine->registers[p2.v.r].v.f; 
			} 
		}
		if(virtual_machine->registers[p1.v.r].t == FLOAT)
		{
			// Check what p2's register holds
			if (virtual_machine->registers[p2.v.r].t == INTEGER)
			{
				// multiply int by float
				virtual_machine->registers[p1.v.r].v.f *= virtual_machine->registers[p2.v.r].v.i; 
			}
			// Check what p2's register holds
			if (virtual_machine->registers[p2.v.r].t == FLOAT)
			{
				// multiply float by float
				virtual_machine->registers[p1.v.r].v.f *= virtual_machine->registers[p2.v.r].v.f; 
			}
		}
	} 
	virtual_machine->instruction_index++;
}

/*This fuction has two parameters. It divides the first parameter, divide it by the second parameter and 
stores it in the register of the first parameter.
written by Sherm Newsome*/
void Div_Func(struct VirtualMachineState *virtual_machine, struct Parameter p1, struct Parameter p2)
{	/*Before we can do any arithmatic, both parameters must be of the same type.*/

	if(p2.t == INTEGER)/*Checks to see if the second parameter type is an int*/
	{
		if(virtual_machine->registers[p1.v.r].t == INTEGER)  /*checks to see the first parameter is an int*/
			virtual_machine->registers[p1.v.r].v.i /= p2.v.i;  /*divides and stores in the register of the first parameter.*/
	
		else if(virtual_machine->registers[p1.v.r].t == FLOAT)
			virtual_machine->registers[p1.v.r].v.f = virtual_machine->registers[p1.v.r].v.f / p2.v.i;
	
	}
	
	else if(p2.t == FLOAT)  /*checks to see if the second parameter's type*/
	{
		if(virtual_machine->registers[p1.v.r].t == FLOAT)/*checks the type of the second parameter*/
			virtual_machine->registers[p1.v.r].v.f /= p2.v.f;/*divides and stores in the register of the first parameter.*/
	
		else if(virtual_machine->registers[p1.v.r].t == INTEGER)/*check the parameter*/
			virtual_machine->registers[p1.v.r].v.f = virtual_machine->registers[p1.v.r].v.i / p2.v.f;/*stores the answer as a float in the first register*/
	}
	
	/*checks to see if the second parameter's type*/
	else if(p2.t==REGISTER)
	{
		if(virtual_machine->registers[p2.v.r].t==INTEGER)/*checks the first parameter's type*/
		{
			/*checks to see if both registers have the same type*/
			if(virtual_machine->registers[p1.v.r].t==INTEGER)
				/*divides the teo parameters*/
				virtual_machine->registers[p1.v.r].v.i/=virtual_machine->registers[p2.v.r].v.i;
			/*the two registers dont match*/
			else if(virtual_machine->registers[p1.v.r].t==FLOAT)
				/*store as a float in the first register*/
				virtual_machine->registers[p1.v.r].v.f=virtual_machine->registers[p1.v.r].v.f / virtual_machine->registers[p2.v.r].v.i;
		}
		
		else if(virtual_machine->registers[p2.v.r].t == FLOAT)/*checks the first parameter's type*/
		{
			/*checks to see if both registers have the same type*/
			if(virtual_machine->registers[p1.v.r].t == FLOAT)
				/*divides the teo parameters*/
				virtual_machine->registers[p1.v.r].v.f /= virtual_machine->registers[p2.v.r].v.f;
			else if(virtual_machine->registers[p1.v.r].t == INTEGER)/*the two registers dont match*/
			{	
				//SETS THE REGISTER VALUE TO A FLOAT
				virtual_machine->registers[p1.v.r].t = FLOAT;
				/*store as a float in the first register*/
				virtual_machine->registers[p1.v.r].v.f = virtual_machine->registers[p1.v.r].v.i / virtual_machine->registers[p2.v.r].v.f;
			}		
		}
	}
	virtual_machine->instruction_index++;
}

/*This function reads in an integer and stores it in a register.
written by Sherm Newsome*/
void Get_Func(struct VirtualMachineState *virtual_machine, struct Parameter p1, struct Parameter p2)
{
	/*Initializes a variable to store input in.*/
	int n;		
	
	/*Reads in an input from the keyboard and stores it as the variable.*/
	scanf("%d",&n);	

	/*Assigns the int to the register.*/
	virtual_machine->registers[p1.v.r].v.i=n;	

	virtual_machine->instruction_index++;
}

/*This functions reads in a float and stores in in a register.
written by Sherm Newsome*/
void Fget_Func(struct VirtualMachineState *virtual_machine, struct Parameter p1, struct Parameter p2)
{
	/*Initialzies a variable to assign the input to.*/
	float d;	

	/*Reads in a input from the keyboard and stores it as the variable.*/
	scanf("%f", &d);	

	/*Assigns the float to the register.*/
	virtual_machine->registers[p1.v.r].v.f = d;	

	virtual_machine->instruction_index++;
}

/*This function displays the contents of the selected registers.
written by Sherm Newsome*/
void Put_Func(struct VirtualMachineState *virtual_machine, struct Parameter p1, struct Parameter p2)
{
	/*checks to see if the parameter is a string*/
	if(p1.t==STRING)
	{
		printf("%s", p1.v.str);	/*displays the contents of the selected register*/
	}
	/*checks the register contents type*/
	else if(p1.t==FLOAT)
	{
		printf("%f",p1.v.f);	/*displays the contents*/
	}
	/*checks the type*/
	else if(p1.t==INTEGER)
	{
		printf("%d",p1.v.i);	/*displays the contents*/
	}
	else if (p1.t == REGISTER)
	{
		if (virtual_machine->registers[p1.v.r].t == STRING)
		{
			printf("%s", virtual_machine->registers[p1.v.r].v.str);	/*displays the contents of the selected register*/
		}
		if (virtual_machine->registers[p1.v.r].t == FLOAT)
		{
			printf("%f", virtual_machine->registers[p1.v.r].v.f);	/*displays the contents of the selected register*/
		}
		if (virtual_machine->registers[p1.v.r].t == INTEGER)
		{
			printf("%i", virtual_machine->registers[p1.v.r].v.i);	/*displays the contents of the selected register*/
		}
	}

	virtual_machine->instruction_index++;
}